"""
分组管理服务
处理用户分组的创建、管理、权限控制和通知协作
"""

from datetime import datetime
from typing import List, Optional, Dict, Any
import uuid
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, func
from fastapi import HTTPException, status

from src.models.group import (
    Group, UserGroup, GroupPermission, GroupType, GroupRole, 
    PermissionAction, ResourceType, GroupCreate, GroupUpdate,
    UserGroupCreate, GroupPermissionCreate, GroupFilter, GroupResponse,
    UserGroupResponse, GroupPermissionResponse
)
from src.models.user import User
from src.utils.logging import get_logger

logger = get_logger(__name__)


class GroupService:
    """分组管理服务类"""

    @staticmethod
    def create_group(db: Session, group_data: GroupCreate, created_by: uuid.UUID) -> Group:
        """创建新分组"""
        # 检查分组名称是否已存在
        existing_group = db.query(Group).filter(Group.name == group_data.name).first()
        if existing_group:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="分组名称已存在"
            )

        # 检查父分组是否存在
        if group_data.parent_id:
            parent_group = db.query(Group).filter(Group.id == group_data.parent_id).first()
            if not parent_group:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="父分组不存在"
                )

        # 创建分组
        group = Group(
            name=group_data.name,
            description=group_data.description,
            type=group_data.type,
            parent_id=group_data.parent_id,
            meta=group_data.metadata or {}
        )
        
        db.add(group)
        db.commit()
        db.refresh(group)

        # 自动将创建者添加为分组所有者
        user_group = UserGroup(
            user_id=created_by,
            group_id=group.id,
            role=GroupRole.ADMIN
        )
        db.add(user_group)
        db.commit()

        logger.info(f"分组创建成功: {group.name} (ID: {group.id})")
        return group

    @staticmethod
    def get_group(db: Session, group_id: uuid.UUID) -> Optional[Group]:
        """获取分组详情"""
        group = db.query(Group).filter(Group.id == group_id).first()
        if not group:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="分组不存在"
            )
        return group

    @staticmethod
    def update_group(db: Session, group_id: uuid.UUID, group_data: GroupUpdate) -> Group:
        """更新分组信息"""
        group = GroupService.get_group(db, group_id)
        
        # 添加类型检查以解决Pylance报告的可选成员访问问题
        if group is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="分组不存在"
            )
        # 修复类型检查问题：添加对group_data的None检查
        if group_data.name is not None and group_data.name != getattr(group, 'name'):
            # 检查新名称是否已存在
            existing_group = db.query(Group).filter(
                and_(Group.name == group_data.name, Group.id != group_id)
            ).first()
            if existing_group:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="分组名称已存在"
                )

        # 更新字段
        if group_data.name is not None:
            setattr(group, 'name', group_data.name)
        if group_data.description is not None:
            setattr(group, 'description', group_data.description)
        if group_data.type is not None:
            setattr(group, 'type', group_data.type)
        if group_data.parent_id is not None:
            # 检查父分组是否存在且不能形成循环引用
            if group_data.parent_id == group_id:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="不能将分组设置为自己的父分组"
                )
            if group_data.parent_id:
                parent_group = db.query(Group).filter(Group.id == group_data.parent_id).first()
                if not parent_group:
                    raise HTTPException(
                        status_code=status.HTTP_400_BAD_REQUEST,
                        detail="父分组不存在"
                    )
            setattr(group, 'parent_id', group_data.parent_id)
        if group_data.is_active is not None:
            setattr(group, 'is_active', group_data.is_active)
        if group_data.metadata is not None:
            setattr(group, 'meta', {**getattr(group, 'meta', {}), **(group_data.metadata or {})})

        setattr(group, 'updated_at', datetime.utcnow())
        db.commit()
        db.refresh(group)

        logger.info(f"分组更新成功: {group.name} (ID: {group.id})")
        return group

    @staticmethod
    def delete_group(db: Session, group_id: uuid.UUID) -> None:
        """删除分组"""
        group = GroupService.get_group(db, group_id)
        
        # 添加类型检查以解决Pylance报告的可选成员访问问题
        if group is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="分组不存在"
            )
        
        # 检查是否有子分组
        child_groups = db.query(Group).filter(Group.parent_id == group_id).count()
        if child_groups > 0:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="请先删除所有子分组"
            )

        # 删除分组关联的用户和权限
        db.query(UserGroup).filter(UserGroup.group_id == group_id).delete()
        db.query(GroupPermission).filter(GroupPermission.group_id == group_id).delete()
        
        # 删除分组
        db.delete(group)
        db.commit()

        logger.info(f"分组删除成功: {group.name} (ID: {group.id})")

    @staticmethod
    def list_groups(db: Session, filters: Optional[GroupFilter] = None) -> List[Group]:
        """获取分组列表"""
        query = db.query(Group)
        
        if filters:
            if filters.name:
                query = query.filter(Group.name.ilike(f"%{filters.name}%"))
            if filters.type:
                query = query.filter(Group.type.in_(filters.type))
            if filters.parent_id is not None:
                query = query.filter(Group.parent_id == filters.parent_id)
            if filters.is_active is not None:
                query = query.filter(Group.is_active == filters.is_active)
            if filters.user_id:
                # 筛选用户所属的分组
                query = query.join(UserGroup).filter(UserGroup.user_id == filters.user_id)

        return query.order_by(Group.name).all()

    @staticmethod
    def add_user_to_group(db: Session, group_id: uuid.UUID, user_data: UserGroupCreate) -> UserGroup:
        """添加用户到分组"""
        group = GroupService.get_group(db, group_id)
        
        # 添加类型检查以解决Pylance报告的可选成员访问问题
        if group is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="分组不存在"
            )
        
        # 检查用户是否存在
        user = db.query(User).filter(User.id == user_data.user_id).first()
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )

        # 检查用户是否已在分组中
        existing_association = db.query(UserGroup).filter(
            and_(UserGroup.user_id == user_data.user_id, UserGroup.group_id == group_id)
        ).first()
        
        if existing_association:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="用户已在分组中"
            )

        # 创建用户-分组关联
        user_group = UserGroup(
            user_id=user_data.user_id,
            group_id=group_id,
            role=user_data.role,
            metadata=user_data.metadata or {}
        )
        
        db.add(user_group)
        db.commit()
        db.refresh(user_group)

        logger.info(f"用户 {user.username} 已添加到分组 {group.name}")
        return user_group

    @staticmethod
    def remove_user_from_group(db: Session, group_id: uuid.UUID, user_id: uuid.UUID) -> None:
        """从分组中移除用户"""
        # 检查关联是否存在
        user_group = db.query(UserGroup).filter(
            and_(UserGroup.user_id == user_id, UserGroup.group_id == group_id)
        ).first()
        
        if not user_group:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不在该分组中"
            )

        # 检查是否是最后一个管理员
        if getattr(user_group, 'role') == GroupRole.ADMIN:
            owner_count = db.query(UserGroup).filter(
                and_(UserGroup.group_id == group_id, UserGroup.role == GroupRole.ADMIN)
            ).count()
            
            if owner_count <= 1:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="不能移除最后一个分组管理员"
                )

        db.delete(user_group)
        db.commit()

        logger.info(f"用户 {user_id} 已从分组 {group_id} 中移除")

    @staticmethod
    def update_user_role(db: Session, group_id: uuid.UUID, user_id: uuid.UUID, new_role: GroupRole) -> UserGroup:
        """更新用户在分组中的角色"""
        user_group = db.query(UserGroup).filter(
            and_(UserGroup.user_id == user_id, UserGroup.group_id == group_id)
        ).first()
        
        if not user_group:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不在该分组中"
            )

        # 检查角色变更是否有效
        if getattr(user_group, 'role') == GroupRole.ADMIN and new_role != GroupRole.ADMIN:
            owner_count = db.query(UserGroup).filter(
                and_(UserGroup.group_id == group_id, UserGroup.role == GroupRole.ADMIN)
            ).count()
            
            if owner_count <= 1:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="不能移除最后一个分组管理员"
                )

        setattr(user_group, 'role', new_role)
        db.commit()
        db.refresh(user_group)

        logger.info(f"用户 {user_id} 在分组 {group_id} 中的角色已更新为 {new_role}")
        return user_group

    @staticmethod
    def get_group_members(db: Session, group_id: uuid.UUID) -> List[UserGroup]:
        """获取分组的所有成员"""
        GroupService.get_group(db, group_id)  # 验证分组存在
        
        return db.query(UserGroup).filter(UserGroup.group_id == group_id).all()

    @staticmethod
    def get_user_groups(db: Session, user_id: uuid.UUID) -> List[UserGroup]:
        """获取用户所属的所有分组"""
        user = db.query(User).filter(User.id == user_id).first()
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户不存在"
            )

        return db.query(UserGroup).filter(UserGroup.user_id == user_id).all()

    @staticmethod
    def add_group_permission(db: Session, group_id: uuid.UUID, permission_data: GroupPermissionCreate) -> GroupPermission:
        """添加分组权限"""
        group = GroupService.get_group(db, group_id)
        
        # 添加类型检查以解决Pylance报告的可选成员访问问题
        if group is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="分组不存在"
            )
        
        # 检查权限是否已存在
        existing_permission = db.query(GroupPermission).filter(
            and_(
                GroupPermission.group_id == group_id,
                GroupPermission.resource_type == permission_data.resource_type,
                GroupPermission.resource_id == permission_data.resource_id,
                GroupPermission.action == permission_data.action
            )
        ).first()
        
        if existing_permission:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="权限已存在"
            )

        permission = GroupPermission(
            group_id=group_id,
            resource_type=permission_data.resource_type,
            resource_id=permission_data.resource_id,
            action=permission_data.action,
            conditions=permission_data.conditions or {}
        )
        
        db.add(permission)
        db.commit()
        db.refresh(permission)

        logger.info(f"分组权限已添加: {group.name} -> {permission_data.action} {permission_data.resource_type}")
        return permission

    @staticmethod
    def remove_group_permission(db: Session, permission_id: uuid.UUID) -> None:
        """移除分组权限"""
        permission = db.query(GroupPermission).filter(GroupPermission.id == permission_id).first()
        if not permission:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="权限不存在"
            )

        db.delete(permission)
        db.commit()

        logger.info(f"分组权限已移除: {permission_id}")

    @staticmethod
    def get_group_permissions(db: Session, group_id: uuid.UUID) -> List[GroupPermission]:
        """获取分组的所有权限"""
        GroupService.get_group(db, group_id)  # 验证分组存在
        
        return db.query(GroupPermission).filter(GroupPermission.group_id == group_id).all()

    @staticmethod
    def check_permission(db: Session, user_id: uuid.UUID, resource_type: ResourceType, 
                        action: PermissionAction, resource_id: Optional[uuid.UUID] = None) -> bool:
        """检查用户对资源的权限"""
        # 获取用户的所有分组
        user_groups = db.query(UserGroup).filter(UserGroup.user_id == user_id).all()
        group_ids = [ug.group_id for ug in user_groups]
        
        if not group_ids:
            return False

        # 构建权限查询
        query = db.query(GroupPermission).filter(
            and_(
                GroupPermission.group_id.in_(group_ids),
                GroupPermission.resource_type == resource_type,
                GroupPermission.action == action
            )
        )

        # 如果指定了资源ID，检查特定资源权限或通用权限
        if resource_id:
            query = query.filter(
                or_(
                    GroupPermission.resource_id == resource_id,
                    GroupPermission.resource_id.is_(None)  # 通用权限
                )
            )
        else:
            query = query.filter(GroupPermission.resource_id.is_(None))

        permissions = query.all()
        return len(permissions) > 0

    @staticmethod
    def get_group_hierarchy(db: Session, group_id: uuid.UUID) -> Dict[str, Any]:
        """获取分组的层级结构（包含所有子分组）"""
        group = GroupService.get_group(db, group_id)
        
        def build_hierarchy(current_group: Group) -> Dict[str, Any]:
            children = db.query(Group).filter(Group.parent_id == current_group.id).all()
            return {
                "id": current_group.id,
                "name": current_group.name,
                "type": current_group.type,
                "children": [build_hierarchy(child) for child in children]
            }

        return build_hierarchy(group)

    @staticmethod
    def get_group_member_count(db: Session, group_id: uuid.UUID) -> int:
        """获取分组的成员数量"""
        return db.query(UserGroup).filter(UserGroup.group_id == group_id).count()

    @staticmethod
    def to_group_response(db: Session, group: Group) -> GroupResponse:
        """将Group模型转换为GroupResponse模型"""
        member_count = GroupService.get_group_member_count(db, getattr(group, 'id'))
        
        return GroupResponse(
            id=getattr(group, 'id'),
            name=getattr(group, 'name'),
            description=getattr(group, 'description'),
            type=getattr(group, 'type'),
            parent_id=getattr(group, 'parent_id'),
            is_active=getattr(group, 'is_active'),
            metadata=getattr(group, 'meta'),
            created_at=getattr(group, 'created_at'),
            updated_at=getattr(group, 'updated_at'),
            member_count=member_count
        )

    @staticmethod
    def to_user_group_response(db: Session, user_group: UserGroup) -> UserGroupResponse:
        """将UserGroup模型转换为UserGroupResponse模型"""
        user = db.query(User).filter(User.id == getattr(user_group, 'user_id')).first()
        group = db.query(Group).filter(Group.id == getattr(user_group, 'group_id')).first()
        
        user_info = {
            "id": getattr(user, 'id'),
            "username": getattr(user, 'username'),
            "email": getattr(user, 'email'),
            "role": getattr(user, 'role')
        } if user else None
        
        group_info = {
            "id": getattr(group, 'id'),
            "name": getattr(group, 'name'),
            "type": getattr(group, 'type')
        } if group else None

        return UserGroupResponse(
            user_id=getattr(user_group, 'user_id'),
            group_id=getattr(user_group, 'group_id'),
            role=getattr(user_group, 'role'),
            joined_at=getattr(user_group, 'joined_at'),
            metadata=getattr(user_group, 'meta'),
            user=user_info,
            group=group_info
        )